package org.tinygroup.sdpm.util;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.tinygroup.commons.tools.StringUtil;
import org.tinygroup.sdpm.common.util.Num62;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;

public class UploadUtils {

    /**
     * 日期格式化对象
     */
    public static final DateFormat MONTH_FORMAT = new SimpleDateFormat(
            "/yyyyMM/ddHHmmss");

    public static final DateFormat YEAR_MONTH_FORMAT = new SimpleDateFormat(
            "yyyyMM");
    protected static final Pattern ILLEGAL_CURRENT_FOLDER_PATTERN = Pattern
            .compile("^[^/]|[^/]$|/\\.{1,2}|\\\\|\\||:|\\?|\\*|\"|<|>|\\p{Cntrl}");

    public static String generateFilename(String path, String ext) {
        return path + MONTH_FORMAT.format(new Date())
                + RandomStringUtils.random(4, Num62.N36_CHARS) + "." + ext;
    }

    public static String generateMonthname() {
        return YEAR_MONTH_FORMAT.format(new Date());
    }

    public static String generateByFilename(String path, String fileName, String ext) {
        return path + fileName + "." + ext;
    }

    /**
     * Sanitizes a filename from certain chars.<br />
     * <p>
     * This method enforces the <code>forceSingleExtension</code> property and
     * then replaces all occurrences of \, /, |, :, ?, *, &quot;, &lt;, &gt;,
     * control chars by _ (underscore).
     *
     * @param filename a potentially 'malicious' filename
     * @return sanitized filename
     */
    public static String sanitizeFileName(final String filename) {

        if (StringUtils.isBlank(filename))
            return filename;

        String name = forceSingleExtension(filename);

        // Remove \ / | : ? * " < > 'Control Chars' with _
        return name.replaceAll("\\\\|/|\\||:|\\?|\\*|\"|<|>|\\p{Cntrl}", "_");
    }

    /**
     * Sanitizes a folder name from certain chars.<br />
     * <p>
     * This method replaces all occurrences of \, /, |, :, ?, *, &quot;, &lt;,
     * &gt;, control chars by _ (underscore).
     *
     * @param folderName a potentially 'malicious' folder name
     * @return sanitized folder name
     */
    public static String sanitizeFolderName(final String folderName) {

        if (StringUtils.isBlank(folderName))
            return folderName;

        // Remove . \ / | : ? * " < > 'Control Chars' with _
        return folderName.replaceAll(
                "\\.|\\\\|/|\\||:|\\?|\\*|\"|<|>|\\p{Cntrl}", "_");
    }

    /**
     * Checks whether a path complies with the FCKeditor File Browser <a href="http://docs.fckeditor.net/FCKeditor_2.x/Developers_Guide/Server_Side_Integration#File_Browser_Requests"
     * target="_blank">rules</a>.
     *
     * @param path a potentially 'malicious' path
     * @return <code>true</code> if path complies with the rules, else
     * <code>false</code>
     */
    public static boolean isValidPath(final String path) {
        if (StringUtils.isBlank(path))
            return false;

        return !ILLEGAL_CURRENT_FOLDER_PATTERN.matcher(path).find();

    }

    /**
     * Replaces all dots in a filename with underscores except the last one.
     *
     * @param filename filename to sanitize
     * @return string with a single dot only
     */
    public static String forceSingleExtension(final String filename) {
        return filename.replaceAll("\\.(?![^.]+$)", "_");
    }

    /**
     * Checks if a filename contains more than one dot.
     *
     * @param filename filename to check
     * @return <code>true</code> if filename contains severals dots, else
     * <code>false</code>
     */
    public static boolean isSingleExtension(final String filename) {
        return filename.matches("[^\\.]+\\.[^\\.]+");
    }

    /**
     * Checks a directory for existence and creates it if non-existent.
     *
     * @param dir directory to check/create
     */
    public static boolean checkDirAndCreate(File dir) {
        if (!dir.exists())
            return dir.mkdirs();
        return false;
    }

    /**
     * Iterates over a base name and returns the first non-existent file.<br />
     * This method extracts a file's base name, iterates over it until the first
     * non-existent appearance with <code>basename(n).ext</code>. Where n is a
     * positive integer starting from one.
     *
     * @param file base file
     * @return first non-existent file
     */
    public static File getUniqueFile(final File file) {
        if (!file.exists())
            return file;

        File tmpFile = new File(file.getAbsolutePath());
        File parentDir = tmpFile.getParentFile();
        int count = 1;
        String extension = FilenameUtils.getExtension(tmpFile.getName());
        String baseName = FilenameUtils.getBaseName(tmpFile.getName());
        do {
            tmpFile = new File(parentDir, baseName + "(" + count++ + ")."
                    + extension);
        } while (tmpFile.exists());
        return tmpFile;
    }

    public static String resolverFilePath(String filePath, String separator) {
        separator = StringUtil.replace(separator, "\\", "/");
        filePath = StringUtil.replace(filePath, "\\", "/");
        return StringUtil.substringAfterLast(filePath, separator);
    }

}
